package com.mjk.common.core.jdbc.sphere.impl.table;

import com.google.common.collect.Range;
import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.util.ObjectUtils;
import com.mjk.common.util.TimeUtils;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.sql.Timestamp;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
 * 时间分片
 * @author Administrator
 *
 */
public class TimeShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<Date>>{
	private final ArcSharding sharding;
	/**
     * 需要空构造方法
     */
    public TimeShardingAlgorithm(ArcSharding sharding) {
    	this.sharding = sharding;
    }
    /**
     * 时间格式
     */
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

	/**
	 * 构建分片后的表明
     */
	 private String buildShardingTable(String logicTableName, Date date) {
         return logicTableName + "_" + TimeUtils.formatTime(date, TimeUtils.DATE_FORMAT_DATEANDONEMON);
	 }

    /**
     * 精确分片
     */
    @Override
	public Collection<String> doSharding(Collection<String> availableTargetNames,
			ComplexKeysShardingValue<Comparable<Date>> shardingValue) {
		List<String> result = new ArrayList<>();
		Collection<Comparable<Date>> value = shardingValue.getColumnNameAndShardingValuesMap().get(sharding.key().toLowerCase());
		if(ObjectUtils.isNotEmpty(value)) {
			for(Comparable<Date> date : value) {
				result.add(buildShardingTable(sharding.table(),TimeUtils.parse(date.toString())));
			}
			result.retainAll(availableTargetNames);
			return result;
		}else {
			Range<Comparable<Date>> betTime = shardingValue.getColumnNameAndRangeValuesMap().get(sharding.key());
			Comparable<Date> lower =  betTime.lowerEndpoint();
			Comparable<Date> upper = betTime.upperEndpoint();
			int diff = TimeUtils.differenceMonth(lower.toString(),upper.toString(),TimeUtils.DATE_FORMAT_DATEONLY);
			if(diff == 0) {//同一个月
				result.add(buildShardingTable(sharding.table(),TimeUtils.parse(lower.toString())));
			}else {
				for(int i=0;i<diff;i++) {
					Calendar c = Calendar.getInstance();
					c.setTime(TimeUtils.parse(TimeUtils.DATE_FORMAT_DATEONLY, lower.toString()));
					c.add(Calendar.MONTH, i);
					result.add(buildShardingTable(sharding.table(),new Timestamp(c.getTimeInMillis())));
				}
			}
			result.retainAll(availableTargetNames);
			return result;
		}
	}

}
